package threadTest.collectionTest;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Vector;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

/**
 * 功能描述: 并发编程 - list
 *  抛出异常   ConcurrentModificationException  并发修改异常
 * 2024/02/22
 * <p>
 * ZhangYi
 */
public class ListTest {
    public static void main(String[] args){
        /*
        1. ArrayList
        2. Vector
        3. Collections.synchronizedList
        4. CopyOnWriteArrayList
        */
        /***
         * CopyOnWriteArrayList（简称COWAL）是Java中并发编程的线程安全集合类，它是ArrayList的线程安全版本。其原理主要体现在“写时复制”（Copy-On-Write, COW）策略上：
         * 数据结构： CopyOnWriteArrayList底层使用一个数组来存储元素，并通过ReentrantLock（可重入锁）来控制对这个数组的修改操作。
         * 读取操作： 读取操作（如get()方法）并不需要获取锁，而是直接返回当前数组引用所指向的数据。这意味着在读取期间，即使有其他线程正在修改列表，读取线程仍能看到旧版本的列表内容，
         *          不会被阻塞。这使得它非常适合于读多写少的并发场景。
         * 写入操作： 当执行添加、删除或更新元素等修改操作（如add(), set(), remove()等方法）时，CopyOnWriteArrayList首先会获取ReentrantLock确保独占访问权。
         * 获取锁后，它并不会直接修改原有的数组，而是创建一个新的数组副本（即“复制”），然后在这个新的副本上进行相应的修改操作。完成修改之后，将原数组引用指向新复制并修改过的数组。
         * 内存一致性： 在JVM层面，CopyOnWriteArrayList利用了volatile关键字保证了对数组引用的修改能够被其他线程及时看到，从而实现线程间的一致性。
         * 优点和缺点：
         * 优点：因为写操作时才复制整个数组，所以读取操作无锁且高效，特别适合于大量读取操作而很少修改的场合。
         * 缺点：每次修改都会产生新的数组副本，如果列表很大或者修改频繁，则可能会造成较大的内存开销以及垃圾回收压力。同时，在高并发写入情况下性能较低，因为每次写入都需要等待所有
         *      读取线程完成后再复制整个数组。此外，由于读取的是旧版本的数组，因此该集合不能保证实时的可见性，即新添加的元素可能无法立即被其他线程看到。
         * 总结来说，CopyOnWriteArrayList的核心思想是在并发环境下通过牺牲写操作效率以换取更高的读取性能和更简单的同步机制。
         */
        //List<Integer> lists = new ArrayList<>(); // 这种情况是不安全的

        // 安全的集合
        //List<Integer> lists = new Vector<>(); // Vector
        //List<Integer> lists = Collections.synchronizedList(new ArrayList<>()); // Collections.synchronizedList
        CopyOnWriteArrayList lists = new CopyOnWriteArrayList<>();

        // 一个线程 执行 多次
        //new Thread(()->{
        //    for(int i = 0; i < 10000; i++){
        //        lists.add(i);
        //    }
        //}).start();

        // 启动10 个线程 , 操作同一个资源

        for (int index = 1; index < 100; index++) {
            final int temp = index;
            new Thread(()-> lists.add(temp), String.valueOf(index)).start();
            System.out.println(lists);
        }
        Object o = lists.get(0);


    }
}
